package at.codebase.web.servlets.user;

import static at.codebase.web.util.i18n.I18NFactory.i18n;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import at.codebase.db.dao.EMessageDao;
import at.codebase.db.dao.EMessageExtDao;
import at.codebase.db.entities.EItem;
import at.codebase.db.entities.EMessage;
import at.codebase.db.entities.EMessageExt;
import at.codebase.db.entities.EMessageExt.UserExt;
import at.codebase.db.entities.EUser;
import at.codebase.db.entities.IMessage;
import at.codebase.web.templates.MainTemplate;
import at.codebase.web.templates.UserProfileTemplate;
import at.codebase.web.templates.message.ItemConversationExtTemplate;
import at.codebase.web.templates.message.ItemConversationTemplate;
import at.codebase.web.templates.message.PrivateConversationExtTemplate;
import at.codebase.web.templates.message.PrivateConversationTemplate;
import at.codebase.web.util.LocalRequest.RequestInformation;
import at.codebase.web.util.template.Template;
import at.codebase.web.util.template.TemplateEngine;

import com.googlecode.objectify.Ref;

/**
 * 
 * @author Lukas Pfeifhofer <lukas.pfeifhofer@devlabs.pro>
 *
 */
public class UserMessages extends AUserProfile {
	
	private static Comparator<IMessage> messageComperator = new Comparator<IMessage>() {
		@Override
		public int compare(IMessage o1, IMessage o2) {
			if (o1.getTimeSend() > o2.getTimeSend()) {
				return 1;
			} else if (o1.getTimeSend() < o2.getTimeSend()) {
				return -1;
			} else {
				return 0;
			}
		}
	};

	private Comparator<IConversation> conversationComperator= new Comparator<UserMessages.IConversation>() {
		@Override
		public int compare(IConversation c1, IConversation c2) {
			if (c1.getTimeLastMessage() > c2.getTimeLastMessage()) {
				return -1;
			} else if (c1.getTimeLastMessage() < c2.getTimeLastMessage()) {
				return 1;
			} else {
				return 0;
			}
		}
	};
	
	public interface IConversation {
		public long getTimeLastMessage();
		public void setTimeLastMessage(long time);
	}
	
	/*
	 * INTERN
	 */
	public static class Conversation implements IConversation {
		
		public ArrayList<Long> unreadIds = new ArrayList<Long>();		
		public ArrayList<EMessage> messages = new ArrayList<EMessage>();
		public long timeLastMessage = Long.MIN_VALUE;
		public EUser partner;
		
		public Conversation(Ref<EUser> partner) {
			this.partner = partner.get();
		}

		public static String genKey(Ref<EUser> addressor, Ref<EUser> recipient){
			long idAddressor = addressor.getKey().getId();
			long idRecipient = recipient.getKey().getId();
			String key;
			if(idAddressor > idRecipient){
				key = idAddressor + "+" + idRecipient;
			}else{
				key = idRecipient + "+" + idAddressor;
			}
			return key;
		}
		
		@Override
		public long getTimeLastMessage(){
			return timeLastMessage;
		}
		
		@Override
		public void setTimeLastMessage(long timeLastMessage){
			this.timeLastMessage = timeLastMessage;
		}
		
	}
	
	public static class PrivateConversation extends Conversation {

		public PrivateConversation(Ref<EUser> partner) {
			super(partner);
		}
		
	}
	
	public static class ItemConversation extends Conversation {

		public EItem item;
		public long timeFirstMessage = Long.MAX_VALUE;
		
		public ItemConversation(Ref<EUser> partner) {
			super(partner);
		}

	}

	/*
	 * EXTERN
	 */
	
	public static class ConversationExt implements IConversation {
		
		public String conversationId;
		
		public ArrayList<Long> unreadIds = new ArrayList<Long>();		
		public ArrayList<EMessageExt> messages = new ArrayList<EMessageExt>();
		public long timeLastMessage = Long.MIN_VALUE;
		public UserExt partner;
		
		public ConversationExt(UserExt partner) {
			this.partner = partner;
		}
		
		@Override
		public long getTimeLastMessage(){
			return timeLastMessage;
		}
		
		@Override
		public void setTimeLastMessage(long timeLastMessage){
			this.timeLastMessage = timeLastMessage;
		}
		
	}
	
	public static class PrivateConversationExt extends ConversationExt {

		public PrivateConversationExt(UserExt partner) {
			super(partner);
		}
		
	}
	
	public static class ItemConversationExt extends ConversationExt {

		public String item;
		public long timeFirstMessage = Long.MAX_VALUE;
		
		public ItemConversationExt(UserExt partner) {
			super(partner);
		}

	}

	@Override
	void buildUserPage(MainTemplate mainTemplate, UserProfileTemplate userProfileTemplate, RequestInformation requestInfo, UserLevel level, RequestType requestType) {
		mainTemplate.setTitle(i18n(requestInfo.getLocale()).string("userMessages_header"));
		mainTemplate.addJSScript("script_user_messages.js");

		EUser user = requestInfo.getUser();
		
		/*
		 * External Messages 
		 */

		final List<EMessageExt> sendMessagesExt = EMessageExtDao.getMessagesByAddressor(user.getId());
		final List<EMessageExt> resievedMessagesExt = EMessageExtDao.getMessagesByRecipient(user.getId());
		
		ArrayList<EMessageExt> messageListExt = new ArrayList<EMessageExt>() {
			{
				addAll(sendMessagesExt);
				addAll(resievedMessagesExt);
			}
		};
		Collections.sort(messageListExt, messageComperator);
		
		HashMap<String, PrivateConversationExt> privateConversationMapExt = new HashMap<String, UserMessages.PrivateConversationExt>();
		HashMap<String, ItemConversationExt> itemConversationMapExt = new HashMap<String, UserMessages.ItemConversationExt>();
		
		for (EMessageExt message : messageListExt) {
			String key;
			if(message.getAddressor() != null){
				key = message.getRecipientExt().getUserId()+"+"+message.getAddressor().getKey().getId();
			}else{
				key = message.getAddressorExt().getUserId()+"+"+message.getRecipient().getKey().getId();
			}
			
			
			
			ConversationExt conversation = null;
			
			if (message.isPm()) {
				//Private conversation
				conversation = privateConversationMapExt.get(key);
				if(conversation == null){					
					if(message.getAddressor() != null){
						conversation = new PrivateConversationExt(message.getRecipientExt());
					}else{
						conversation = new PrivateConversationExt(message.getAddressorExt());
					}
					privateConversationMapExt.put(key, (PrivateConversationExt) conversation);
				}
			}else{
				conversation = itemConversationMapExt.get(key);
				if(conversation == null){					
					if(message.getAddressor() != null){
						conversation = new ItemConversationExt(message.getRecipientExt());
					}else{
						conversation = new ItemConversationExt(message.getAddressorExt());
					}
					((ItemConversationExt) conversation).item = message.getItem();
					itemConversationMapExt.put(key, (ItemConversationExt) conversation);
				}
			}
			/*else {
				//Item conversation
				conversation = itemConversationMapExt.get(key);
				if(conversation == null){
					if(user.getId().longValue() == message.getAddressor().getKey().getId()){
						conversation = new ItemConversationExt(message.getRecipient());	
					}else{
						conversation = new ItemConversationExt(message.getAddressor());
					}
					if(message.getTimeSend() < ((ItemConversationExt) conversation).timeFirstMessage)
						conversation.timeLastMessage = message.getTimeSend();
					((ItemConversationExt) conversation).item = message.getItem().get();
					itemConversationMapExt.put(key, (ItemConversationExt) conversation);
				}
				
			}
			*/
			
			if(message.getTimeSend() > conversation.getTimeLastMessage())
				conversation.setTimeLastMessage(message.getTimeSend());
			
			//if(message.isUnread() && message.getRecipient().getKey().getId() == user.getId().longValue())
			//	conversation.unreadIds.add(message.getId());
			conversation.conversationId = message.getConversationId();
			conversation.messages.add(message);
		}
		
		ArrayList<PrivateConversationExt> privateConversationListExt = new ArrayList<PrivateConversationExt>(privateConversationMapExt.values());
		ArrayList<ItemConversationExt> itemConversationListExt = new ArrayList<ItemConversationExt>(itemConversationMapExt.values());
		
		//Sort Conversations
		Collections.sort(privateConversationListExt, conversationComperator);
		Collections.sort(itemConversationListExt, conversationComperator);

		
		//System.out.println(privateConversationListExt.toString());
		//System.out.println(itemConversationListExt.toString());
		
		/*
		 * Internal Messages
		 */
		
		final List<EMessage> sendMessages = EMessageDao.getMessagesByAddressor(user.getId());
		final List<EMessage> resievedMessages = EMessageDao.getMessagesByRecipient(user.getId());
		
		ArrayList<EMessage> messageList = new ArrayList<EMessage>() {
			{
				addAll(sendMessages);
				addAll(resievedMessages);
			}
		};
		
		//Sort Messages
		Collections.sort(messageList, messageComperator);
		
		HashMap<String, PrivateConversation> privateConversationMap = new HashMap<String, UserMessages.PrivateConversation>();
		HashMap<String, ItemConversation> itemConversationMap = new HashMap<String, UserMessages.ItemConversation>();
		
		for (EMessage message : messageList) {
			String key = Conversation.genKey(message.getAddressor(), message.getRecipient());
			
			Conversation conversation;
			
			if (message.isPm()) {
				//Private conversation
				conversation = privateConversationMap.get(key);
				if(conversation == null){
					if(user.getId().longValue() == message.getAddressor().getKey().getId()){
						conversation = new PrivateConversation(message.getRecipient());	
					}else{
						conversation = new PrivateConversation(message.getAddressor());
					}
					privateConversationMap.put(key, (PrivateConversation) conversation);
				}
			} else {
				//Item conversation
				conversation = itemConversationMap.get(key);
				if(conversation == null){
					if(user.getId().longValue() == message.getAddressor().getKey().getId()){
						conversation = new ItemConversation(message.getRecipient());	
					}else{
						conversation = new ItemConversation(message.getAddressor());
					}
					if(message.getTimeSend() < ((ItemConversation) conversation).timeFirstMessage)
						conversation.timeLastMessage = message.getTimeSend();
					((ItemConversation) conversation).item = message.getItem().get();
					itemConversationMap.put(key, (ItemConversation) conversation);
				}
				
			}
			
			if(message.getTimeSend() > conversation.timeLastMessage)
				conversation.timeLastMessage = message.getTimeSend();
			if(message.isUnread() && message.getRecipient().getKey().getId() == user.getId().longValue())
				conversation.unreadIds.add(message.getId());
			
			conversation.messages.add(message);
		}
		
		ArrayList<PrivateConversation> privateConversationList = new ArrayList<PrivateConversation>(privateConversationMap.values());
		ArrayList<ItemConversation> itemConversationList = new ArrayList<ItemConversation>(itemConversationMap.values());
		
		ArrayList<ItemConversation> itemSellerConversationList = new ArrayList<ItemConversation>();
		ArrayList<ItemConversation> itemCustomerConversationList = new ArrayList<ItemConversation>();
		
		//Sort Conversations
		Collections.sort(privateConversationList, conversationComperator);
		Collections.sort(itemConversationList, conversationComperator);
		
		for (ItemConversation conversation : itemConversationList) {
			if (conversation.item != null) {
				if (conversation.item.checkSeller(requestInfo.getUser().getId())) {
					itemSellerConversationList.add(conversation);
				} else {
					itemCustomerConversationList.add(conversation);
				}
			}
		}
		

		
		Template userMessagesT = TemplateEngine.getTemplate("user/site_profile_messages.html");
		userMessagesT.setText("randomKey", nextToken());

		//Internal
		int sumUnreadPrivate = 0;
		ArrayList<Template> privateConversationsTemplates = new ArrayList<Template>();
		for (PrivateConversation conversation : privateConversationList) {
			PrivateConversationTemplate conversationTemplate = new PrivateConversationTemplate(requestInfo, conversation);
			privateConversationsTemplates.add(conversationTemplate);
			sumUnreadPrivate += conversation.unreadIds.size();
		}

		int sumUnreadSeller = 0;
		ArrayList<Template> itemSellerConversationTemplates = new ArrayList<Template>();
		for (ItemConversation conversation : itemSellerConversationList) {
			ItemConversationTemplate conversationTemplate = new ItemConversationTemplate(requestInfo, conversation);
			itemSellerConversationTemplates.add(conversationTemplate);
			sumUnreadSeller += conversation.unreadIds.size();
		}

		int sumUnreadCustomer = 0;
		ArrayList<Template> itemCustomerConversationTemplates = new ArrayList<Template>();
		for (ItemConversation conversation : itemCustomerConversationList) {
			ItemConversationTemplate conversationTemplate = new ItemConversationTemplate(requestInfo, conversation);
			itemCustomerConversationTemplates.add(conversationTemplate);
			sumUnreadCustomer += conversation.unreadIds.size();
		}

		if(sumUnreadPrivate > 0)
			userMessagesT.setHTML("privateMessagesUnread", "<b>("+sumUnreadPrivate+")</b>");
		if(sumUnreadCustomer > 0)
			userMessagesT.setHTML("customerMessagesUnread", "<b>("+sumUnreadCustomer+")</b>");
		if(sumUnreadSeller > 0)
			userMessagesT.setHTML("sellerMessagesUnread", "<b>("+sumUnreadSeller+")</b>");

		if(privateConversationsTemplates.size() > 0){
			userMessagesT.setTemplates("privateMessagesList", privateConversationsTemplates);	
		}else{
			userMessagesT.setHTML(
					"privateMessagesList",
					"<div class=\"userMessagesNoMessage\">"
							+ i18n(requestInfo.getLocale()).string("userMessages_message_noMessages")
							+ "</div>");
		}
		
		if(itemSellerConversationTemplates.size() > 0){
			userMessagesT.setTemplates("sellerMessagesList", itemSellerConversationTemplates);	
		}else{
			userMessagesT.setHTML(
					"sellerMessagesList",
					"<div class=\"userMessagesNoMessage\">"
							+ i18n(requestInfo.getLocale()).string("userMessages_message_noMessages")
							+ "</div>");
		}
		
		if(itemCustomerConversationTemplates.size() > 0){
			userMessagesT.setTemplates("customerMessagesList", itemCustomerConversationTemplates);	
		}else{
			userMessagesT.setHTML(
					"customerMessagesList",
					"<div class=\"userMessagesNoMessage\">"
							+ i18n(requestInfo.getLocale()).string("userMessages_message_noMessages")
							+ "</div>");
		}
		
		
		userMessagesT.setTemplates("sellerMessagesList", itemSellerConversationTemplates);
		userMessagesT.setTemplates("customerMessagesList", itemCustomerConversationTemplates);
		
		//External
		ArrayList<Template> privateConversationsExtTemplates = new ArrayList<Template>();
		for (PrivateConversationExt conversation : privateConversationListExt) {
			PrivateConversationExtTemplate conversationTemplate = new PrivateConversationExtTemplate(requestInfo, conversation);
			privateConversationsExtTemplates.add(conversationTemplate);
		}
		userMessagesT.setTemplates("privateMessagesListExt", privateConversationsExtTemplates);
		
		ArrayList<Template> itemConversationsExtTemplates = new ArrayList<Template>();
		for (ItemConversationExt conversation : itemConversationListExt) {
			ItemConversationExtTemplate conversationTemplate = new ItemConversationExtTemplate(requestInfo, conversation);
			itemConversationsExtTemplates.add(conversationTemplate);
		}
		userMessagesT.setTemplates("itemMessagesListExt", itemConversationsExtTemplates);
	
		userProfileTemplate.setContent(userMessagesT);
		userProfileTemplate.setText("randomKey", nextToken());
	}

}